package cn.starrysky108.simpleerp.core.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Carl Lee
 * 类型转换工具
 */
@Slf4j
@Component
public class CastUtil {
    private static ObjectMapper mapper;

    @Autowired
    public CastUtil(ObjectMapper mapper) {
        CastUtil.mapper = mapper;

    }


    /**
     * Object转换为其他类型
     *
     * @param fromObj obj
     * @param clazz   目标类型
     * @param <T>     泛型
     */
    public static <T> T objToAny(Object fromObj, Class<T> clazz) {
        if (ObjectUtils.isEmpty(fromObj)) {
            return null;
        }
        return mapper.convertValue(fromObj, clazz);

    }

    /**
     * Object转为LIst
     *
     * @param fromObj obj
     * @param clazz   List值的目标类型
     * @param <T>     List值泛型
     * @return ArrayList
     */
    public static <T> List<T> objToList(Object fromObj, Class<T> clazz) {
        if (ObjectUtils.isEmpty(fromObj)) {
            return null;
        }
        try {
            List<T> result = new ArrayList<>();
            if (fromObj instanceof List<?>) {
                for (Object o : (List<?>) fromObj) {
                    result.add(objToAny(o, clazz));
                }
                return result;
            }
        } catch (ClassCastException e) {
            log.error("类型转换失败");
            log.error(e.getMessage());
        }
        return null;
    }


    /**
     * obj转为map
     * 注：key为null的元素会被忽略
     *
     * @param fromObj   强转对象
     * @param keyType   Map的key类型
     * @param valueType Map的value类型
     * @param <K>       Key泛型
     * @param <V>       Value泛型
     * @return Map HashMap<K,V></K,V>
     */
    public static <K, V> Map<K, V> objToMap(Object fromObj, Class<K> keyType, Class<V> valueType) {
        if (ObjectUtils.isEmpty(fromObj)) {
            return null;
        }
        HashMap<K, V> result = new HashMap<>(10);
        if (fromObj instanceof HashMap<?, ?>) {
            ((HashMap<?, ?>) fromObj).forEach(
                    (key, value) -> {
                        if (key != null) {
                            result.put(objToAny(key, keyType), objToAny(value, valueType));
                        }
                    });
        }
        return result;
    }

    /**
     * obj转json字符串
     */
    public static String objToJson(Object obj) {
        if (ObjectUtils.isEmpty(obj)) {
            return null;
        }
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.error("obj转json错误：" + obj);
            return e.getMessage();
        }
    }

    /**
     * json转object
     */
    public static <T> T jsonToObj(String json, Class<T> clazz) {
        if (!StringUtils.hasText(json)) {
            return null;
        }
        try {
            return mapper.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            log.error("obj转json错误：" + json);
        }
        return null;
    }

    /**
     * json转Map
     *
     * @return hash map
     */
    public static Map<?, ?> jsonToMap(String json) {
        if (!StringUtils.hasText(json)) {
            return null;
        }
        try {
            return mapper.readValue(json, Map.class);
        } catch (JsonProcessingException e) {
            log.error("obj转json错误：" + json);
        }
        return null;
    }

    /**
     * list元素类型转换
     */
    public static <T> List<T> castList(List<?> list, Class<T> clazz) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        List<T> result = new ArrayList<>(list.size());
        list.forEach(obj -> result.add((objToAny(obj, clazz))));
        return result;
    }

    /**
     * map元素类型转换，可以转key与value
     *
     * @param map       原始map
     * @param keyType   目标key类型
     * @param valueType 目标value类型
     * @return HashMap<K, V>
     */
    public static <K, V> Map<K, V> castMap(Map<?, ?> map, Class<K> keyType, Class<V> valueType) {
        if (ObjectUtils.isEmpty(map)) {
            return null;
        }
        Map<K, V> result = new HashMap<>(map.size());
        map.forEach((
                (key, value) -> {
                    if (value != null) {
                        result.put(objToAny(key, keyType), objToAny(value, valueType));
                    }
                }));
        return result;
    }
}
